use super::RawTask;
use core::task::{RawWaker, RawWakerVTable, Waker};

impl RawTask {
    pub(crate) fn task_waker(&self) -> Waker {
        let raw_waker = RawWaker::new((self as *const Self).cast::<()>(), &TASKWAKER_VTABLE);
        unsafe { Waker::from_raw(raw_waker) }
    }
}

const RAWWAKER_VTABLE: RawWakerVTable =
    RawWakerVTable::new(waker_clone, waker_wake, waker_wake_by_ref, waker_drop);

unsafe fn waker_clone(this: *const ()) -> RawWaker {
    let task = unsafe { &*this.cast::<RawTask>() };
    task.inc_ref();
    RawWaker::new(this, &RAWWAKER_VTABLE)
}

unsafe fn waker_wake(this: *const ()) {
    let task = unsafe { &*this.cast::<RawTask>() };
    task.wake();
    task.dec_ref();
}

unsafe fn waker_wake_by_ref(this: *const ()) {
    let task = unsafe { &*this.cast::<RawTask>() };
    task.wake();
}

unsafe fn waker_drop(this: *const ()) {
    let task = unsafe { &*this.cast::<RawTask>() };
    task.dec_ref();
}

const TASKWAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
    waker_clone,
    waker_wake_by_ref,
    waker_wake_by_ref,
    task_waker_drop,
);

unsafe fn task_waker_drop(_this: *const ()) {}
